<?php
/**
 * This file is part of Hyperf Mall.
 *
 * @link     https://gitee.com/scwlkj/hypref_mall
 * contact  hyperf_mall@163.com
 */

namespace App\Repository\Member;


use App\Cache\TokenCache;
use App\Constants\MemberConstant;
use App\Constants\Message;
use App\Exception\BaseException;
use App\Model\Member\MemberModel;
use App\Repository\BaseRepository;
use App\Repository\MemberBalanceRepository;
use App\Repository\MemberOpenIdRepository;
use App\Repository\MemberPointRepository;
use App\Repository\MessageRepository;
use App\Repository\PointLogRepository;
use App\Service\Activity\CouponReceiveService;
use App\Service\Orders\OrderService;
use App\Utils\DB;
use App\Utils\Log;
use Hyperf\Di\Annotation\Inject;
use PHPUnit\Exception;

class MemberRepository extends BaseRepository
{
    /**
     * @Inject
     * @var MemberModel
     */
    protected $model;

    /**
     * @Inject
     * @var OrderService
     */
    protected $orderService;

    /**
     * @Inject
     * @var CouponReceiveService
     */
    protected CouponReceiveService $couponReceiveService;

    /**
     * @Inject
     * @var MemberPointRepository
     */
    protected MemberPointRepository $memberPointRepository;

    /**
     * @Inject
     * @var MemberBalanceRepository
     */
    protected MemberBalanceRepository $memberBalanceRepository;

    /**
     * @Inject
     * @var LevelsRepository
     */
    protected LevelsRepository $levelsRepository;

    /**
     * @inject
     * @var MemberOpenIdRepository
     */
    protected MemberOpenIdRepository $memberOpenIdRepository;

    /**
     * @inject
     * @var MessageRepository
     */
    protected MessageRepository $messageRepository;

    public function updateByConditions($conditions, $data): bool
    {
        $res = parent::updateByConditions($conditions, $data);
        if (array_intersect(TokenCache::getInstance(TokenCache::TYPE_APP)->getTokenFields(), array_keys($data))) {
            $memberList = $this->_searchFactor($conditions)->get()->toArray();
            foreach ($memberList as $value) {
                TokenCache::getInstance(TokenCache::TYPE_APP)->createToken($value);
            }
        }
        return $res;
    }

    /**
     * Notes: 用户中心
     * Author: Bruce.z
     * DateTime: 2022/7/19 13:43
     * @param int $member_id
     * @return array
     */
    public function info(int $member_id):array
    {
        $point = $this->memberPointRepository->getOne(['member_id'=>$member_id], ['use_point']);
        $money = $this->memberBalanceRepository->getOne(['member_id'=>$member_id], ['enable_balance']);
        $info = $this->getOne(['id'=>$member_id],['username','image','level']);
        $level = $this->levelsRepository->getOne(['id'=>$info['level']], ['name']);

        $coupon = $this->couponReceiveService->memberCount($member_id);
        $user = [
            'point'=>$point['use_point']??0,
            'money'=>$money['enable_balance']??0,
            'level'=>$level['name']??'初始等级',
            'coupon'=>$coupon??0,
        ];

        $user['new_message'] = $this->messageRepository->getCount(['member_id'=>$member_id,'status'=>Message::MS_NOT_READ]);
        $user['order'] = $this->orderService->appMemberIndex($member_id);
        return array_merge($info, $user);
    }

    /**
     * Notes: open_id 注册会员信息
     * Author: Bruce.z
     * DateTime: 2022/7/30 10:20
     * @param $openid
     * @param $image
     * @param $username
     * @return array
     * @throws BaseException
     */
    public function register($openid, $image, $username): array
    {
        $data = [
            'image'=>$image,
            'username'=>$username,
        ];

        DB::beginTransaction();
        try {
            $member_model = $this->baseAdd($data);
            $this->memberOpenIdRepository->baseAdd([
                'member_id'=>$member_model['id'],
                'open_id'=>$openid,
                'app_type'=>'xcx'
            ]);
            DB::commit();
        }catch (Exception $exception){
            DB::rollBack();
            Log::getInstance()->error('数据插入失败', [$exception->getMessage()]);
            throw new BaseException(BaseException::BASE_ERROR, '初始化会员失败');
        }

        return $this->getOne(['id' => $member_model['id']]);
    }

    /**
     * Notes: pc端注册
     * Author: Bruce.z
     * DateTime: 2022/9/26 9:31
     * @param $data
     * @return array
     * @throws BaseException
     */
    public function registerPc($data): array
    {
        $user_name = $data['userName'];
        $member = $this->getOne(['username' => $user_name],['id']);
        if(!empty($member)){
            throw new BaseException(BaseException::BASE_ERROR,'用户名已存在');
        }

        $_data['auth_key'] = random(32);
        $_data['password'] = self::makePassword($data['password'], $_data['auth_key']);
        $_data['username'] = $user_name;

        $member_model = $this->baseAdd($_data);
        return $this->getOne(['id' => $member_model['id']],['username','id','image','tel','sex']);
    }

    /**
     * Notes: pc 端重置密码
     * Author: Bruce.z
     * DateTime: 2022/10/19 20:13
     * @param int $member_id
     * @param string $oldPassword
     * @param string $newPassword
     * @return bool
     * @throws BaseException
     */
    public function resetPassword(int $member_id,string $oldPassword, string $newPassword): bool
    {
        $re = $this->getOne(['id' => $member_id],['username','id','image','tel','sex','status','auth_key','password']);
        if (empty($re)) {
            throw new BaseException(BaseException::BASE_ERROR, '账号或密码错误');
        }

        if (self::makePassword($oldPassword, $re['auth_key']) !== $re['password']) {
            throw new BaseException(BaseException::BASE_ERROR, '旧密码输入错误');
        }

        $random_str = random(32);
        $_data = [
            'auth_key'=>$random_str,
            'password'=>self::makePassword($newPassword, $random_str),
        ];

        return $this->updateByConditions(['id'=>$member_id], $_data);
    }

    /**
     * Notes: 获取密码
     *
     * @param string $password
     * @param string $auth_key
     * @return string
     */
    public static function makePassword(string $password, string $auth_key): string
    {
        return md5($auth_key . md5($password));
    }

    /**
     * Notes: 登录
     * @param string $username
     * @param string $password
     * @return array<string, int|string>
     * @throws BaseException
     */
    public function login(string $username, string $password): array
    {
        $re = $this->getOne(['username' => $username],['username','id','image','tel','sex','status','auth_key','password']);
        if (empty($re)) {
            throw new BaseException(BaseException::BASE_ERROR, '账号或密码错误');
        }

        if (self::makePassword($password, $re['auth_key']) !== $re['password']) {
            throw new BaseException(BaseException::BASE_ERROR, '账号或密码错误');
        }

        if ($re['status'] == MemberConstant::STATUS_DISABLE) {
            throw new BaseException(BaseException::BASE_ERROR, '账号已被禁用，请联系管理员');
        }

        $token_data = [
            'id' => $re['id'],
            'username' => $re['username'],
        ];
        $re['token'] = TokenCache::getInstance(TokenCache::TYPE_PC)->createToken($token_data);

        return [
            'username' => $re['username'],
            'token' => $re['token'],
            'status' => $re['status'],
            'image' => $re['image']
        ];
    }


}
